/*
 * RefCounted.h
 *
 *	Author: stravant
 *	Description:
 *		
 */

#ifndef REFCOUNTED_H_
#define REFCOUNTED_H_

#include "../core/Atomic.h"

template <class T>
class RefCountedThreadsafe {
public:
	RefCountedThreadsafe() {}
	~RefCountedThreadsafe() {}

	void ref() const {
		mRefCount.inc();
	}
	void release() const {
		if (mRefCount.dec() == 1)
			delete static_cast<T*>(this);
	}
private:
	mutable AtomicUInt32 mRefCount;
};


template <class T>
class RefCounted {
public:
	RefCounted() {}
	~RefCounted() {}

	void ref() const {
		++mRefCount;
	}
	void release() const {
		if (!(--mRefCount))
			delete static_cast<const T*>(this);
	}
private:
	mutable int mRefCount;
};


template <class T>
class Ref {
public:
	Ref(): mPtr(0) {}

	Ref(T* p) : mPtr(p) {
		if (mPtr)
			mPtr->ref();
	}

	Ref(const Ref<T>& r) : mPtr(r.mPtr) {
		if (mPtr)
			mPtr->ref();
	}

	template <typename U>
	Ref(const Ref<U>& r) : mPtr(r.get()) {
	if (mPtr)
		mPtr->ref();
	}

	~Ref() {
		if (mPtr)
			mPtr->release();
	}

	T* get() const {return mPtr;}
	operator T*() const {return mPtr;}
	T* operator->() const {return mPtr;}

	//Change ownership of the pointer to something else
	T* orphan() {
		T* retVal = mPtr;
		mPtr = 0;
		return retVal;
	}

	Ref<T>& operator=(T* p) {
		// AddRef first so that self assignment should work
		if (p)
			p->ref();
		if (mPtr)
			mPtr->release();
		mPtr = p;
		return *this;
	}

	Ref<T>& operator=(const Ref<T>& r) {
		return *this = r.mPtr;
	}

	template <typename U>
	Ref<T>& operator=(const Ref<U>& r) {
		return *this = r.get();
	}

	void swap(T** pp) {
		T* p = mPtr;
		mPtr = *pp;
		*pp = p;
	}

	void swap(Ref<T>& r) {
		swap(&r.mPtr);
	}

//	bool operator==(const Ref<T>& r) const {
//		return mPtr == r.mPtr;
//	}
//
//	bool operator!=(const Ref<T>& r) const {
//		return mPtr != r.mPtr;
//	}

protected:
	T* mPtr;
};

#endif /* REFCOUNTED_H_ */
